import random,os
from PIL import Image,ImageFont,ImageDraw,ImageFilter


def random_string(length=32): # 生成32位随机字符串，原本是为了生成随机文件名，用于保存上传的头像，所以默认32位
    import random
    string='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
    return ''.join(random.choice(string) for i in range(length))


def random_color():
    r=random.randint(0,255)
    g=random.randint(0,255)
    b=random.randint(0,255)
    if r*0.299+g*0.578+b*0.114>=100: # 它们的和越小，颜色越深。from https://blog.csdn.net/qq_36843675/article/details/79448051和https://blog.csdn.net/dKnightL/article/details/107222075
        return (r,g,b)
    else:
        return random_color() # 递归，直到满足条件才停止，避免产生深色画布


def generate_verification_code_image(length=4):
    size=130,50
    image=Image.new('RGB',size=size,color=random_color()) # 创建画布，返回Image对象。https://pillow.readthedocs.io/en/stable/
    font=ImageFont.truetype(os.path.abspath(os.path.dirname(__file__))+'/times.ttf',size=40) # 创建字体，是系统中的Times New Roman 常规，从系统中复制出来就是这个文件名，不能修改文件名，否则前端加载不出验证码图片(服务端控制台报错OSError: cannot open resource)，即访问者的系统中需有这个字体。不建议只写'times.ttf'，虽然和代码文件在同一个目录，但服务器命令行找不到字体文件('./times.ttf'也不行)，pycharm可以，所以为了跨平台，用绝对路径
    draw=ImageDraw.Draw(image) # 创建ImageDraw对象，相当于创建画笔，参数是画布
    str=random_string(length)
    for i,value in enumerate(str): # 绘制验证码
        draw.text((5+random.randint(4,7)+25*i,1+random.randint(2,8)+2*i),text=value,fill=random_color(),font=font) # 第一个参数是每个字符的左上角的坐标，横坐标里25是固定字符间距，前面是随机字符间距，实际字符间距等于它们的和；text是要绘制的字符，fill是字符颜色
    for j in range(random.randint(5,8)): # 绘制干扰直线
        # 将画布平均分成上下两部分，使每条线的第一个端点在上部分，第二个端点在下部分，干扰效果更好
        x1=random.randint(0,130)
        y1=random.randint(0,50/2)
        x2=random.randint(0,130)
        y2=random.randint(50/2,50)
        draw.line(((x1,y1),(x2,y2)),fill=random_color()) # 第一个参数是每条线的端点坐标，fill是线条颜色
    for k in range(random.randint(5,8)): # 绘制干扰弧线from https://blog.csdn.net/qq_34356800/article/details/86744042，将他的size[0]改成了130，size[1]改成了50
        start=(-50,-50) # 起始位置在外边看起来才会像弧线
        end=(130+10,random.randint(0,50+10))
        draw.arc(start+end,0,360,fill=random_color())
    for m in range(130): # 绘制干扰点
        for n in range(50):
            number=random.randint(1,100)
            if number>90: # 只有10%的概率画点，概率再大的话影响人识别
                draw.point((m,n),fill=random_color())
    '''
    for i in range(40): # 绘制干扰点和干扰线 from https://www.cnblogs.com/Zzbj/p/13797672.html
        draw.point([random.randint(0,130),random.randint(0,50)],fill=random_color())
        x=random.randint(0,130)
        y=random.randint(0,50)
        draw.arc((x,y,x+4,y+4),0,90,fill=random_color())
    '''
    image=image.filter(ImageFilter.SMOOTH) # 返回添加了过滤器的Image对象，SMOOTH让图片模糊
    # image.show() # 展示图片
    return str,image


if __name__ == '__main__':
    generate_verification_code_image() # 测试image.show()时只运行这个文件